package com.kk.crowd.mvc.config;

import com.kk.crowd.constant.CrowdConstant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Configuration
// 启用 Web 环境下权限控制功能
@EnableWebSecurity
// 启用全局方法权限管理功能
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class CrowdfundingSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CrowdUserDetailsService crowdUserDetailsService;

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    // 每次调用这个方法时会检查 IOC 容器中是否有了对应的 bean，如果有就不会真正执行这 个函数，因为 bean 默认是单例的
    // 可以使用@Scope(value="")注解控制是否单例
  /*  @Bean
    public BCryptPasswordEncoder getBCryptPasswordEncoder() {
        return new BCryptPasswordEncoder ( );
    }*/

    // 与 SpringSecurity 环境下用户登录相关
    @Override
    protected void configure(AuthenticationManagerBuilder builder) throws Exception {

        // 临时使用内存版登录的模式测试代码
        // builder.inMemoryAuthentication().withUser("tom").password("123456").roles("ADMIN");

        // 1、装配userDetailsService对象
        // 2、在配置类中的 configure(AuthenticationManagerBuilder)方法中应用自定义密码加密规则
        //logger.info ("对象："+passwordEncoder);

        builder
                .userDetailsService (crowdUserDetailsService)
                .passwordEncoder (passwordEncoder)
        ;
    }

    // 与 SpringSecurity 环境下请求授权相关
    @Override
    protected void configure(HttpSecurity security) throws Exception {
        // 放行首页、静态资源
        security
                .authorizeRequests ( )    // 对请求进行授权
                .antMatchers ("/admin/to/login/page.html")    // 针对登录页进行设置
                .permitAll ( )            // 无条件访问
                .antMatchers ("/bootstrap/**")    // 针对静态资源进行设置，无条件访问
                .permitAll ( )                    // 针对静态资源进行设置，无条件访问
                .antMatchers ("/crowd/**")       // 针对静态资源进行设置，无条件访问
                .permitAll ( )                    // 针对静态资源进行设置，无条件访问
                .antMatchers ("/css/**")         // 针对静态资源进行设置，无条件访问
                .permitAll ( )                    // 针对静态资源进行设置，无条件访问
                .antMatchers ("/fonts/**")       // 针对静态资源进行设置，无条件访问
                .permitAll ( )                    // 针对静态资源进行设置，无条件访问
                .antMatchers ("/img/**")         // 针对静态资源进行设置，无条件访问
                .permitAll ( )                    // 针对静态资源进行设置，无条件访问
                .antMatchers ("/jquery/**")      // 针对静态资源进行设置，无条件访问
                .permitAll ( )                    // 针对静态资源进行设置，无条件访问
                .antMatchers ("/layer/**")       // 针对静态资源进行设置，无条件访问
                .permitAll ( )                    // 针对静态资源进行设置，无条件访问
                .antMatchers ("/script/**")      // 针对静态资源进行设置，无条件访问
                .permitAll ( )                    // 针对静态资源进行设置，无条件访问
                .antMatchers ("/ztree/**")       // 针对静态资源进行设置，无条件访问
                .permitAll ( )
                //.antMatchers ("/admin/page.html")// 针对分页显示Admin数据设定访问控制
                // .hasRole("经理")					// 要求具备经理角色
                //.access ("hasRole('经理') OR  hasAuthority('user:get')")  // 要求具备“经理”角色和“user:get”权限二者之一
                .anyRequest ( )                          // 任意请求
                .authenticated ( )                        // 认证后访问
                .and ( )
                .exceptionHandling ( )
                .accessDeniedHandler (new AccessDeniedHandler ( ) {
                    @Override
                    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
                        request.setAttribute ("exception", new Exception (CrowdConstant.MESSAGE_ACCESS_DENIED));
                        request.getRequestDispatcher ("/WEB-INF/system-error.jsp").forward (request, response);
                    }
                })
                .and ( )
                .csrf ( )                                      // 防跨站请求伪造功能
                .disable ( )                                  // 禁用
                .formLogin ( )                                  // 开启表单登录的功能
                .loginPage ("/admin/to/login/page.html")
                .loginProcessingUrl ("/security/do/login.html")                 // 指定处理登录请求的地址
                .defaultSuccessUrl ("/admin/to/main/page.html")                    // 指定登录成功后前往的地址
                .usernameParameter ("loginAcct")
                .passwordParameter ("userPswd")
                .and ( )
                .logout ( )                        // 开启退出登录功能
                .logoutUrl ("/seucrity/do/logout.html")            // 指定退出登录地址
                .logoutSuccessUrl ("/admin/to/login/page.html")    // 指定退出成功以后前往的地址
        ;
    }
}
